﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Collections;

namespace SerialTool
{
    class FrameManager
    {


        SerialPort serial;

        List<IFrameFilter> listFilter = new List<IFrameFilter>();


        byte[] rxBuffer = new byte[16 * 1024];
        byte[] frameBuffer = new byte[16 * 1024];

        int frameLength = 0;
        bool metHeader = false;


        public FrameManager(SerialPort port)
        {
            if (port == null) return;
            this.serial = port;
            this.serial.DataReceived += new SerialDataReceivedEventHandler(Serial_DataReceived);
        }

        void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            SerialPort port = sender as SerialPort;


            int length = port.Read(rxBuffer, 0, port.BytesToRead);

            for (int i = 0; i < length; i++)
            {
                switch (rxBuffer[i])
                {
                    case 0x10:
                        if (!metHeader)
                        {
                            frameBuffer[frameLength] = 0x10;
                            frameLength++;
                            if (frameLength >= 2 && frameBuffer[1] != 0x02)
                            {
                                frameBuffer[0] = 0x10;
                                frameLength = 1;
                            }
                        }
                        metHeader = !metHeader;
                        break;
                    case 0x02:
                        if (metHeader)
                        {
                            frameBuffer[0] = 0x10;
                            frameBuffer[1] = 0x02;
                            frameLength = 2;
                        }
                        else if (frameLength >= 2)
                        {
                            frameBuffer[frameLength] = rxBuffer[i];
                            frameLength++;
                        }
                        metHeader = false;
                        break;
                    case 0x03:
                        if (metHeader) //获取一个新的数据帧
                        {
                            frameBuffer[frameLength] = 0x03;
                            frameLength++;

                            CheckFrame(frameBuffer, frameLength);
                            frameLength = 0;

                        }
                        else if (frameLength >= 2)
                        {
                            frameBuffer[frameLength] = rxBuffer[i];
                            frameLength++;
                        }
                        metHeader = false;
                        break;
                    default:
                        if (frameLength >= 2)
                        {
                            frameBuffer[frameLength] = rxBuffer[i];
                            frameLength++;
                        }
                        metHeader = false;
                        break;
                }
                if (frameLength >= frameBuffer.Length)
                {
                    frameLength = 0;
                    metHeader = false;
                }
            }


        }



        public void AddFilter(IFrameFilter filter)
        {
            lock (((ICollection)listFilter).SyncRoot)
            {
                listFilter.Add(filter);
            }
        }

        void CheckFrame(byte[] buffer, int length)
        {
            //长度校验
            int dataLen = (buffer[2] << 8) + buffer[3];

            if (dataLen != length - 6) return;

            //CRC16校验

            UInt16 crc = CRC16.ComputeCRC16(buffer, 2, dataLen);

            UInt16 crcRx = (UInt16)(buffer[length - 3] + (buffer[length - 4] << 8));

            if (crc != crcRx) return;

            Frame frame = new Frame(buffer, length);

            lock (((ICollection)listFilter).SyncRoot)
            {
                foreach (IFrameFilter filter in listFilter)
                {
                    if (filter.Match(frame))
                    {
                        filter.AddFrame(frame);
                    }
                }
            }


        }











    }
}
